目前這個系列已挑選ChatGPT、前端&React相關章節出版成書!
感謝大家的閱讀與支持!
《用 ChatGPT 詠唱來點亮 React & 前端技能樹》
歷經重新整理、校正、編排、與修改後,讓章節內容之間的銜接更平順,除了補充上更多的解說之外,甚至有部分章節為重新撰寫的內容,讓理解變得更輕鬆!
目前已在天瓏書局、博客來、金石堂等通路都買得到了! 也有電子書的選擇!
歡迎各位點擊連結選購,謝謝大家~
從這個章節開始,遇到有關JS (JavaScript)的內容,我會預設改用TS (TypeScript)來寫
向ChatGPT提問的自定指示中,也會改成這樣
有TypeScript相關問題,請看我的上一篇介紹:
【Day10】ChatGPT請教教我:TypeScript!Enum!泛型 !
沒問題就Go Go了!
有關class相關的用法,即使是資工本科生,在學習的時候也有可能會遇到一些困難
讓我們看看ChatGPT是如何介紹Class的
當然可以!我會用簡單易懂的方式來介紹什麼是 class。
什麼是 Class?
在程式設計中,class(類別)是一種用來創建物件(object)的藍圖或模板。它定義了一個物件的特性(屬性)和行為(方法),可以看作是封裝了資料和相關操作的容器。
舉例來說,假設我們要描述一個狗的類型,它會有一些特性,如名字、品種、年齡等,同時也會有一些行為,比如吠叫、奔跑等。這些特性和行為可以被封裝在一個狗的類別中。
Class 的基本結構
以下是一個 TypeScript 中的 class 的基本結構範例:
class Dog { // 屬性 name: string; breed: string; age: number; // 建構子 constructor(name: string, breed: string, age: number) { this.name = name; this.breed = breed; this.age = age; } // 方法 bark() { console.log(`${this.name}在叫!`); } run() { console.log(`${this.name}在奔跑!`); } }
如何使用 Class?
要使用這個狗的類別,你可以這樣做:
// 創建一個狗的物件 const myDog = new Dog("旺財", "柴犬", 3); // 存取屬性或呼叫方法 console.log(`我家狗狗的品種是${myDog.breed}`); myDog.bark(); myDog.run();
這樣,你就可以使用這個狗的類別來創建不同的狗物件,並且存取它們的特性和行為。
這只是 class 的基本概念,還有許多進階的用法和概念,但希望這個簡單的介紹對你有幫助!如果你有任何問題或需要進一步的解釋,請隨時告訴我。
上面提供了語法,但卻不知道什麼時候會需要用到class
或是常見使用情境是什麼
所以來問問看ChatGPT
Class 在程式設計中有著重要的作用,它的常見用途包括以下幾個方面:
- 物件導向程式設計(Object-Oriented Programming, OOP):Class 是物件導向程式設計的基礎。它可以幫助程式設計師將資料和相關操作封裝在一個單元中,使得程式碼更具結構性和模組化。
- 模組化開發:透過 class,可以將相關的資料和功能組織成一個模組,這樣可以方便管理和維護程式碼。
- 程式碼重複使用:你可以根據 class 創建多個物件,這些物件會共享相同的特性和行為,從而節省了重複編寫相似程式碼的工作量。
- 抽象化和封裝:Class 允許你將特定的實現細節隱藏起來,只向外部提供必要的接口,這樣可以降低程式的複雜度,提高代碼的可讀性。
- 繼承:Class 可以透過繼承機制,讓一個 class 繼承另一個 class 的特性和行為,進一步提高程式碼的重用性。
- 多型:Class 的繼承和多型機制讓你可以針對不同類型的物件,使用相同的介面進行操作,這樣可以撰寫更通用和靈活的程式碼。
總的來說,Class 是一個強大的程式設計工具,它可以幫助你組織和管理程式碼,使得程式更容易理解、維護和擴展。在前端開發中,Class 常被用來建構 UI 元件、管理狀態、定義資料模型等等。因此,對於你作為一名前端工程師的目標來說,熟練掌握 Class 將是非常重要的一環。
講了很多新的專有名詞,講了許多好處
但沒有範例還是有點難懂,但得到了很多新關鍵字
先請他直接針對各點再解釋並給予範例吧
好的,我會針對以上提到的各點,提供相應的範例和詳細解釋。
1. 物件導向程式設計(OOP)
物件導向程式設計是一種程式設計範式,它將程式中的資料和相關操作封裝在一個物件中。
範例:
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } introduce() { console.log(`我叫${this.name},今年${this.age}歲。`); } } const john = new Person("John", 30); john.introduce(); // 輸出:我叫John,今年30歲。
這裡我們定義了一個
Person
的 class,它有name
和age
兩個屬性,以及一個introduce
方法,用來介紹自己。通過new Person(...)
我們可以創建一個Person
的物件。2. 模組化開發
Class 可以幫助我們將相關的資料和功能組織成一個模組,使得程式碼更易於管理。
範例:
// person.ts class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } introduce() { console.log(`我叫${this.name},今年${this.age}歲。`); } } export default Person; // main.ts import Person from './person'; const john = new Person("John", 30); john.introduce(); // 輸出:我叫John,今年30歲。
這裡我們將
Person
的 class 定義在person.ts
檔案中,然後在main.ts
中引入並使用它。這樣可以使得程式碼更模組化,方便維護。3. 程式碼重複使用
透過 class,我們可以創建多個物件,這些物件共享相同的特性和行為。
範例:
class Circle { radius: number; constructor(radius: number) { this.radius = radius; } getArea() { return Math.PI * this.radius ** 2; } } const circle1 = new Circle(5); const circle2 = new Circle(8); console.log(circle1.getArea()); // 輸出:78.54 console.log(circle2.getArea()); // 輸出:201.06
在這個例子中,我們創建了兩個不同半徑的圓形物件
circle1
和circle2
,它們都擁有相同的getArea
方法,但返回的面積值會根據半徑而變化。4. 抽象化和封裝
Class 允許你將特定的實現細節隱藏起來,只向外部提供必要的接口。
範例:
class BankAccount { private balance: number = 0; deposit(amount: number) { this.balance += amount; } withdraw(amount: number) { if (amount <= this.balance) { this.balance -= amount; } else { console.log("餘額不足!"); } } getBalance() { return this.balance; } } const account = new BankAccount(); account.deposit(1000); account.withdraw(500); console.log(account.getBalance()); // 輸出:500
在這個例子中,我們定義了一個
BankAccount
的 class,它有一個私有的balance
屬性,以及deposit
、withdraw
和getBalance
方法來操作和獲取帳戶餘額。這樣可以隱藏balance
的實際實現細節。這是一些 class 的基本用法範例,希望這些範例能幫助你更好地理解 class 的各種作用和用途。如果有任何問題,請隨時告訴我!
可以看到他每一項都給予範例了
其中提到了一個關鍵的專有名詞:物件導向程式設計(OOP)
物件導向程式設計(Object-Oriented Programming, OOP)是一種程式設計範式,它以"物件"(object)為基礎,將資料和相關操作封裝在一個單元中,透過這種方式來組織和管理程式碼。
在 OOP 中,每個物件都是類別(class)的一個實例。類別是一種藍圖或模板,它定義了一個物件的特性(屬性)和行為(方法)。屬性代表物件的狀態或特徵,而方法則定義了物件可以進行的操作或行為。
以下是一個簡單的物件導向程式設計的範例:
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } introduce() { console.log(`我叫${this.name},今年${this.age}歲。`); } } const john = new Person("John", 30); john.introduce(); // 輸出:我叫John,今年30歲。
在這個例子中,我們定義了一個
Person
的 class,它有name
和age
兩個屬性,以及一個introduce
方法,用來介紹自己。透過new Person(...)
我們創建了一個Person
的物件john
。OOP 的核心概念:
- 封裝(Encapsulation):將相關的資料和功能封裝在一個類別中,並對外部隱藏實現細節。
- 繼承(Inheritance):允許一個類別繼承另一個類別的特性和行為,可以重用現有的程式碼。
- 多型(Polymorphism):允許相同的介面用於不同的數據類型或物件,使得程式碼更靈活和通用。
如何學習 OOP?
步驟 1: 了解基本概念
首先,你需要理解封裝、繼承和多型這三個基本的 OOP 概念。
步驟 2: 熟悉類別和物件的建立
學會如何定義類別,並且創建類別的物件。
步驟 3: 學習封裝和存取控制
了解如何使用封裝來隱藏物件的實現細節,以及如何設定不同的存取控制(public、private、protected)。
步驟 4: 掌握繼承和多型
學習如何使用繼承來建立物件之間的階層關係,並了解多型如何使得相同的介面可以應用在不同的物件上。
步驟 5: 實際應用
將所學應用到實際的程式開發中,建立自己的物件和類別,並逐漸熟練 OOP 的技巧。
步驟 6: 閱讀相關資源和範例
閱讀相關的書籍、教學文章,並參考各種範例,進一步加深對 OOP 的理解和應用。
總的來說,學習 OOP 需要不斷的練習和實踐,隨著時間的推移,你將會變得更加熟練和自信。如果你有任何具體的問題或需要進一步的解釋,請隨時告訴我!
當然,讓我詳細解釋物件導向程式設計(OOP)的核心概念:
1. 封裝(Encapsulation):
封裝是指將相關的資料和行為(方法)封裝在一個單位(類別)中,並對外部隱藏內部的實現細節,僅向外提供必要的介面。這樣做的目的是為了降低系統的複雜度,提高程式碼的可讀性和可維護性。
範例:
class BankAccount { private balance: number = 0; deposit(amount: number) { this.balance += amount; } withdraw(amount: number) { if (amount <= this.balance) { this.balance -= amount; } else { console.log("餘額不足!"); } } getBalance() { return this.balance; } }
在這個例子中,
balance
是一個私有屬性,只能在BankAccount
內部訪問。外部無法直接存取balance
,只能透過deposit
、withdraw
和getBalance
方法來進行操作。2. 繼承(Inheritance):
繼承是指一個類別(子類別)可以繼承另一個類別(父類別)的特性和行為。子類別可以使用父類別的屬性和方法,並且可以擴展或修改它們,同時也可以新增自己的屬性和方法。
範例:
class Animal { name: string; constructor(name: string) { this.name = name; } makeSound() { console.log("動物發出聲音。"); } } class Dog extends Animal { bark() { console.log("狗狗在叫!"); } } const myDog = new Dog("旺財"); myDog.makeSound(); // 輸出:動物發出聲音。 myDog.bark(); // 輸出:狗狗在叫!
在這個例子中,
Dog
類別繼承了Animal
類別,因此它可以使用name
屬性和makeSound
方法。同時,Dog
類別也新增了自己的方法bark
。3. 多型(Polymorphism):
多型是指相同的介面可以應用在不同的物件上,這樣可以提高程式的靈活性和通用性。在多型中,不同的類別可以實現相同的介面或抽象類別,但具體的實現方式可以各自不同。
範例:
class Shape { calculateArea(): number { return 0; } } class Circle extends Shape { radius: number; constructor(radius: number) { super(); this.radius = radius; } calculateArea(): number { return Math.PI * this.radius ** 2; } } class Rectangle extends Shape { width: number; height: number; constructor(width: number, height: number) { super(); this.width = width; this.height = height; } calculateArea(): number { return this.width * this.height; } } const circle = new Circle(5); const rectangle = new Rectangle(4, 6); console.log(circle.calculateArea()); // 輸出:78.54 console.log(rectangle.calculateArea()); // 輸出:24
在這個例子中,
Shape
是一個抽象類別,它定義了一個計算面積的方法。Circle
和Rectangle
類別都繼承了Shape
並實現了calculateArea
方法,但實現的方式各自不同,這就是多型的一個例子。這就是物件導向程式設計的核心概念:封裝、繼承和多型。透過這些概念,我們可以建立更為結構化、靈活且可維護的程式碼。如果你有任何進一步的問題或需要更詳細的解釋,請隨時告訴我!
前面在講述跟「封裝」有關的議題時,都會用到一個新的關鍵字: private
更前面講解要如何學習物件導向時,也有提到「存取控制(public、private、protected)」等
因此繼續拿關鍵字來深入詢問ChatGPT
當然,讓我來進一步深入講解如何設定不同的存取控制(public、private、protected):
存取修飾符:
在 TypeScript 中,可以使用存取修飾符來指定類別的成員(屬性和方法)的存取範圍,這有助於控制對類別內部資料的訪問權限。
1.
public
:
public
表示成員可以在類別內部和外部被訪問。這是預設的存取修飾符,如果未指定存取修飾符,則默認為public
。範例:
class Person { public name: string; constructor(name: string) { this.name = name; } public introduce() { console.log(`我叫${this.name}。`); } } const john = new Person("John"); console.log(john.name); // 可以訪問 john.introduce(); // 可以呼叫
2.
private
:
private
表示成員僅在類別內部可以被訪問,外部無法訪問。範例:
class BankAccount { private balance: number = 0; deposit(amount: number) { this.balance += amount; } getBalance() { return this.balance; } } const account = new BankAccount(); account.deposit(1000); // 可以呼叫 console.log(account.balance); // 無法訪問,因為是 private
3.
protected
:
protected
表示成員可以在類別內部以及子類別中被訪問,但無法在外部訪問。範例:
class Animal { protected sound: string; constructor(sound: string) { this.sound = sound; } makeSound() { console.log(this.sound); } } class Dog extends Animal { bark() { console.log(`${this.sound} ${this.sound}!`); } } const dog = new Dog("汪汪"); dog.makeSound(); // 可以呼叫 dog.bark(); // 可以呼叫 console.log(dog.sound); // 無法訪問,因為是 protected
使用情境:
- 使用
public
當你希望該成員可以在類別內外被訪問時。- 使用
private
當你希望限制該成員僅在類別內部被訪問時。- 使用
protected
當你希望該成員可以在類別內部以及子類別中被訪問時。存取修飾符可以幫助你有效地控制類別成員的訪問範圍,以保護資料的安全性和提高程式碼的可維護性。當你在設計類別時,請根據需求合理地選擇適當的存取修飾符。如果有任何進一步的問題或需要更詳細的解釋,請隨時告訴我!
OK,上面講這麼多,也講了一堆優點
像是結構化、靈活、可維護之類的
但我認為人類是一種不見棺材不掉淚,沒有痛過無法痛改前非的物種(?)
所以來請他提供一下,如果不使用class的話
到底會有什麼問題,請他提供對照
如果不使用物件導向的概念來撰寫程式,會導致程式碼難以維護、擴展和理解,也會增加程式碼的複雜度。以下我會透過範例來比較使用和不使用物件導向的情況。
1. 沒有使用物件導向的情況:
範例:
let person1Name = "John"; let person1Age = 30; let person2Name = "Jane"; let person2Age = 25; function introducePerson1() { console.log(`我叫${person1Name},今年${person1Age}歲。`); } function introducePerson2() { console.log(`我叫${person2Name},今年${person2Age}歲。`); } introducePerson1(); // 輸出:我叫John,今年30歲。 introducePerson2(); // 輸出:我叫Jane,今年25歲。
2. 使用物件導向的情況:
範例:
class Person { name: string; age: number; constructor(name: string, age: number) { this.name = name; this.age = age; } introduce() { console.log(`我叫${this.name},今年${this.age}歲。`); } } const person1 = new Person("John", 30); const person2 = new Person("Jane", 25); person1.introduce(); // 輸出:我叫John,今年30歲。 person2.introduce(); // 輸出:我叫Jane,今年25歲。
問題與比較:
- 可維護性:在第一個範例中,當我們想要新增更多的人員時,必須手動添加變數和函數,這樣會使得程式碼變得雜亂且難以維護。在第二個範例中,我們可以輕鬆地創建新的
Person
物件,使得程式碼更具結構性和維護性。- 可擴展性:在第一個範例中,如果我們想要為每個人員添加更多的資訊(例如地址、電話等),則必須修改相應的變數和函數。在第二個範例中,我們只需在
Person
類別中新增屬性和方法即可。- 程式碼重複使用:在第一個範例中,每個函數都是針對特定的人員,無法複用。在第二個範例中,我們可以創建多個
Person
物件,它們共享相同的introduce
方法。- 程式碼結構:使用物件導向的方式可以使程式碼更有結構性和模組化,使得每個元件的職責更加清晰明確。
總的來說,物件導向的概念使得程式碼更易於維護、擴展和理解,並且提高了程式碼的重複使用性。因此,在較大型的專案或需要長期維護的情況下,使用物件導向是非常重要的。
OK以上就是我們拿Class相關的概念來詢問ChatGPT的結果
對話紀錄放在這邊:https://chat.openai.com/share/ef51f0a2-014c-483d-999c-6a90baff7cae
我認為物件導向本身就不是一個好懂的概念
可能要實際在撰寫程式著碰到痛點,才知道物件導向的好處
我自己大學時花了一整個學期來學習物件導向,當時仍然沒有很融會貫通
直到工作實際碰到痛點,才開始把以前學過的東西重新撿回來
花了大量時間重新學習,把程式碼重構整理成有使用物件導向的模式
痾,對。我入職的時候裡面的程式碼沒有在跟你物件導向的
所有的變數就這樣全域零散在各處,超過二十個以上零散的變數你能想像嗎
希望以上的範例與教學可以幫助到正在學習物件導向的各位
我是物件導向信徒的前端工程師一宵三筵,我們明天見~